package com.faxsun.core.service.impl;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import mblog.core.persist.dao.UserDao;
import mblog.core.pojos.User;
import mblog.core.utils.BeanMapUtils;
import mtons.modules.exception.MtonsException;
import mtons.modules.lang.Const;
import mtons.modules.lang.EntityStatus;
import mtons.modules.pojos.Page;
import mtons.modules.pojos.UserProfile;
import mtons.modules.utils.MD5Helper;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.faxsun.core.persist.entity.UserPO;
import com.faxsun.core.pojos.enums.AccountType;
import com.faxsun.core.service.UserService;
import com.faxsun.core.service.shop.impl.AccountOperation;

public class UserServiceImpl implements UserService {

	private static final String cacheName = "userServiceCache";

	@Autowired
	private UserDao userDao;

	@Autowired
	private AccountOperation accountOperation;

	@Override
	@Transactional
	public UserProfile login(String username, String password) {
		// FIXME:优化验证流程或重构
		UserPO po = null;

		// 用户名为faxsun，读取本地信息
		if (username.equals("faxsun")) {
			po = userDao.get(username);
			String encodedPassword = password + "{1}";
			MessageDigest mDigest;
			try {
				mDigest = MessageDigest.getInstance("SHA1");
				byte[] result = mDigest.digest(encodedPassword.getBytes());
				StringBuffer sb = new StringBuffer();
				for (int i = 0; i < result.length; i++) {
					sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
				}
				encodedPassword = sb.toString();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			if (!po.getPassword().equals(encodedPassword)) {
				po = null;
			}
		} else {
			// 发送到电商验证用户名和密码
			// 电商返回userpo信息
			try {
				po = accountOperation.login(username, password);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				throw new RuntimeException();
			}

			// 根据userpo信息，判断本地是否存在
			if (po.getUserId() != null && po.getUserId() > 0L) {
				UserPO localPO = userDao.getByUserId(po.getUserId());
				if (localPO == null) {
					// 本地信息不存在，则保存
					userDao.save(po);
				} else {
					// 若已存在,则使用本地信息
					po = localPO;
				}
			} else {
				// 用户名密码验证失败
				po = null;
			}
		}

		// 将PO转换为userProfile
		UserProfile u = null;
		if (po != null) {
			// 信息验证通过
			if (po.getStatus() == Const.STATUS_CLOSED) {
				throw new MtonsException("您的账户已被封禁");
			}
			// 设置登陆时间
			po.setLastLogin(Calendar.getInstance().getTime());
			u = BeanMapUtils.copyPassport(po);
		}
		return u;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void register(User user) {
		Assert.notNull(user, "Parameter user can not be null!");

		Assert.hasLength(user.getUsername(), "用户名(邮箱)不能为空!");
		Assert.hasLength(user.getPassword(), "密码不能为空!");
		Assert.hasLength(user.getName(), "昵称不能为空!");

		UserPO check = userDao.get(user.getUsername());
		Assert.isNull(check, "用户名（邮箱）已经存在，请直接登录或更换邮箱!");

		UserPO po = new UserPO();

		BeanUtils.copyProperties(user, po);

		Date current = Calendar.getInstance().getTime();
		po.setPassword(MD5Helper.md5(user.getPassword()));
		po.setStatus(EntityStatus.ENABLED);
		po.setCreated(current);
		po.setUpdated(current);

		try {
			Long uid = accountOperation.register(user.getUsername(), user.getPassword());
			if (uid == null || uid <= 0L) {
				throw new RuntimeException("服务器错误，请稍后再试!");
			}

			po.setUserId(uid);
			userDao.save(po);
			user.setUid(uid);
		} catch (Exception e) {
			e.printStackTrace();
			// 触发事务回滚
			// FIXME: 触发回滚
			throw new RuntimeException(e.getMessage());
		}
	}

	/**
	 * 用户更新用户实体中的Email,name和lastlogin
	 */
	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#user.id")
	public UserProfile update(User user) {
		//TODO: 完善更新方法
		UserPO po = userDao.get(user.getId());
		if (null != po) {
			po.setEmail(user.getEmail());
			po.setName(user.getName());
			po.setLastLogin(user.getLastLogin());
			userDao.update(po);
		}

		return BeanMapUtils.copyPassport(po);
	}

	@Override
	@Transactional
	public User get(long id) {
		UserPO po = userDao.get(id);
		User ret = null;
		if (po != null) {
			ret = BeanMapUtils.copy(po);
		}
		return ret;
	}

	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public UserProfile updateAvatar(long id, String path) {
		UserPO po = userDao.get(id);
		if (po != null) {
			po.setAvatar(path);
			po.setUpdated(new Date());
		}
		return BeanMapUtils.copyPassport(po);
	}

	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public UserProfile updateName(long id, String name) {
		UserPO po = userDao.get(id);
		if (po != null) {
			po.setName(name);
			po.setUpdated(new Date());
		}
		return BeanMapUtils.copyPassport(po);
	}

	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public void updatePassword(long id, String newPassword) {
		UserPO po = userDao.get(id);

		Assert.hasLength(newPassword, "密码不能为空!");

		if (null != po) {
			po.setPassword(MD5Helper.md5(newPassword));
		}
	}

	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public void updatePassword(long id, String oldPassword, String newPassword) {
		UserPO po = userDao.get(id);

		Assert.hasLength(newPassword, "密码不能为空!");

		if (po != null) {
			Assert.isTrue(MD5Helper.md5(oldPassword).equals(po.getPassword()), "当前密码不正确");
			po.setPassword(MD5Helper.md5(newPassword));
		}
	}

	@Override
	@Transactional
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public void updateStatus(long id, int status) {
		UserPO po = userDao.get(id);

		if (po != null) {
			po.setStatus(status);
		}
	}

	@Override
	@Transactional(readOnly = true)
	public void paging(Page page) {
		List<UserPO> list = userDao.paging(page);
		List<User> rets = new ArrayList<User>();

		for (UserPO po : list) {
			User u = BeanMapUtils.copy(po);
			rets.add(u);
		}
		page.setResults(rets);
	}

	@Override
	@Transactional(rollbackFor = { Exception.class })
	@Cacheable(value = cacheName, key = "'findUserPOBy'+#uid")
	public UserPO findUserPOBy(long uid) {
		return userDao.get(uid);
	}

	@Override
	@Transactional(readOnly = true)
	public UserPO findUserByCustomerId(long customerId) {
		return userDao.getByUserId(customerId);
	}

	@Override
	@Transactional()
	@CacheEvict(value = cacheName, key = "'findUserPOBy'+#id")
	public UserProfile updateSignature(long id, String signature) {
		UserPO po = userDao.get(id);
		if (po != null) {
			po.setSignature(signature);
			po.setUpdated(new Date());
		}
		return BeanMapUtils.copyPassport(po);
	}

	@Override
	@Transactional
	public UserProfile findByThirdId(String openId, AccountType accountType) {
		UserPO userPO = null;

		switch (accountType) {
		case WECHAT:
			userPO = userDao.getByThirdId(openId);
			if (userPO == null) {
				userPO = userDao.getByUnionId(openId);
			}
			break;
		default:
			break;
		}
		UserProfile user = null;
		if (userPO != null) {
			user = BeanMapUtils.copyPassport(userPO);
		}
		return user;
	}

	@Override
	@Transactional
	public UserProfile createLocalUser(UserPO user) {
		// TODO Auto-generated method stub
		userDao.save(user);

		return BeanMapUtils.copyPassport(user);
	}
}
